home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 112 / EnigmaAmiga112CD.iso / dalla rivista / giochi in rete / sorgenti_amislate / ilbm.c < prev    next >
C/C++ Source or Header  |  1995-08-05  |  24KB  |  811 lines

  1. #ifndef ILBM_C
  2. #define ILBM_C
  3.  
  4. #define PIXELBUFFERSIZE 256    /* 256 bytes = 2048 pixels across */
  5.  
  6. #define MASK_NOMASK  0
  7. #define MASK_HASMASK 1
  8. #define MASK_TRANSP  2
  9. #define MASK_LASSO   3
  10.  
  11. #define COMP_NONE    0
  12. #define COMP_BYTERUN 1
  13.  
  14. #include <stdio.h>
  15. #include <string.h>
  16. #include <stdlib.h>
  17. #include <exec/types.h>
  18. #include <exec/memory.h>
  19. #include <libraries/dos.h>
  20. #include <libraries/iffparse.h>
  21. #include <clib/dos_protos.h>
  22. #include <clib/iffparse_protos.h>
  23. #include <clib/intuition_protos.h>
  24. #include <clib/graphics_protos.h>
  25. #include <clib/exec_protos.h>
  26. #include <datatypes/pictureclass.h>    /* for struct BitMapHeader... */
  27.  
  28. #include "amislate.h"
  29. #include "ilbm.h"
  30. #include "drawlang.h"
  31. #include "remote.h"
  32. #include "tools.h"
  33. #include "byterun.h"
  34. #include "drawrexx_aux.h"
  35.  
  36. #define ID_ILBM MAKE_ID('I','L','B','M')
  37. #define ID_BMHD MAKE_ID('B','M','H','D')
  38. #define ID_CMAP MAKE_ID('C','M','A','P')
  39. #define ID_BODY MAKE_ID('B','O','D','Y')
  40.  
  41. struct ThreeUnsignedBytes {
  42.     UBYTE ubRed;
  43.     UBYTE ubGreen;
  44.     UBYTE ubBlue;
  45. };
  46.  
  47. extern struct PaintInfo PState;
  48. extern BOOL BLoadIFFPalettes, BExpandIFFWindow, BProtectInter, BNetConnect;
  49. extern struct Screen * Scr;
  50. extern struct Window * DrawWindow;
  51. extern char szWinTitle[];
  52. extern char * pcWhatToAbort;
  53.  
  54. /* Our own flag!  If TRUE, we are waiting for a resize to complete
  55.    before we draw the picture.  */
  56. BOOL BIFFLoadPending = FALSE;
  57.  
  58. /* These are all the local variables for LoadIFF.  But to resize with
  59.    a partner, we need to leave LoadIFF and return to it later.  This is
  60.    implemented by splitting LoadIFF into LoadIFF1() and LoadIFF2(), and 
  61.    setting the flag BIFFLoadPending, which will trigger a call to LoadIFF2()
  62.    when the window has been resized. */
  63. static struct IFFHandle * SlateIFF = NULL;
  64. static BOOL BCompression;
  65. static BOOL BPenMarked[MAXCOLORS];    
  66. static UBYTE *CMAPdata = NULL;
  67. static struct StoredProperty *BMHDProp = NULL;
  68. static struct BitMapHeader   *BMHDhead = NULL;
  69. static struct StoredProperty *CMAPProp = NULL;
  70. static struct StoredProperty *BODYProp = NULL;    
  71. static UBYTE ubPenArray[MAXCOLORS];    /* Yes, we do a max of 256 colors! */
  72. static UBYTE *ubPixelArray=NULL;    /* holds up to one row of delicious IFF pixels! */
  73. static UBYTE *ubByteArray=NULL;        /* holds up to 8 interbyteleaved rows */
  74. static int i,nBytesRead,nPlane,nBytesPerRow;
  75. static int x1,x2,y1,y2,nOutputWidth,nOutputHeight;
  76. static int nNewWidth, nNewHeight;
  77.  
  78.  
  79.  
  80. /* Used for the TempRaster of ReadArrayPixel8 */
  81. static struct RastPort tempRaster;
  82. static struct BitMap   rMsBitMap;
  83.     
  84.  
  85. /* Used to read proper settings */
  86. BOOL * BOurProtectInter, * BOurExpand, * BOurLoadPalette;
  87.  
  88. /* ARexx temp settings */
  89. BOOL BRexxProtectInter, BRexxExpand, BRexxLoadPalette;
  90.  
  91. BOOL LoadIFF1(int nFromCode, char *szFileName)
  92. {
  93.     pcWhatToAbort = "IFF Load";
  94.     
  95.     /* Choose the correct set of options */
  96.     if (nFromCode == FROM_REXX)
  97.     {
  98.         BOurProtectInter = &BRexxProtectInter;
  99.         BOurExpand       = &BRexxExpand;
  100.         BOurLoadPalette  = &BRexxLoadPalette;
  101.     }
  102.     else
  103.     {
  104.         BOurProtectInter = &BProtectInter;
  105.         BOurExpand       = &BExpandIFFWindow;
  106.         BOurLoadPalette  = &BLoadIFFPalettes;
  107.     }
  108.     
  109.     /* Make sure a load isn't already in progress; if it is, flush it! */
  110.     if (SlateIFF != NULL)
  111.     {
  112.          CleanUpIFF(SlateIFF);
  113.     }
  114.     
  115.     /* All pens default to not-changed. */
  116.     for (i=0;i<MAXCOLORS;i++) BPenMarked[i]=FALSE;
  117.     
  118.     /* protect the interface colors */
  119.     BPenMarked[0] = TRUE + *BOurProtectInter;    /* 1=minimal protect if no */
  120.     BPenMarked[1] = TRUE + *BOurProtectInter;    /* 2=absolute protect if yes */
  121.     BPenMarked[2] = TRUE + *BOurProtectInter;
  122.     BPenMarked[3] = TRUE + *BOurProtectInter;
  123.     
  124.     SlateIFF = AllocIFF();
  125.     if (SlateIFF == NULL) return(FALSE);
  126.  
  127.     SlateIFF->iff_Stream = (ULONG) Open(szFileName, MODE_OLDFILE);
  128.     if (SlateIFF->iff_Stream == 0) 
  129.     {
  130.         CleanUpIFF(SlateIFF);
  131.         return(FALSE);
  132.     }
  133.     
  134.     InitIFFasDOS(SlateIFF);
  135.     if (OpenIFF(SlateIFF, IFFF_READ) != 0L)
  136.     {
  137.         CleanUpIFF(SlateIFF);
  138.         return(FALSE);
  139.     }
  140.     
  141.     /* Specify which chunks we want stored */
  142.     PropChunk(SlateIFF,ID_ILBM,ID_BMHD);
  143.     PropChunk(SlateIFF,ID_ILBM,ID_CMAP);
  144.     StopChunk(SlateIFF,ID_ILBM,ID_BODY);
  145.  
  146.     /* Scan that bad boy! */
  147.     ParseIFF(SlateIFF, IFFPARSE_SCAN);
  148.     
  149.     /* First get info from BitMap Header */
  150.     BMHDProp = FindProp(SlateIFF, ID_ILBM, ID_BMHD);
  151.     if (BMHDProp == NULL) 
  152.     {
  153.         CleanUpIFF(SlateIFF);
  154.         return(FALSE);
  155.     }
  156.     
  157.     BMHDhead = (struct BitMapHeader *) BMHDProp->sp_Data;
  158.  
  159. #ifdef DEBUG_ILBM    
  160.     printf("BitMapHeaderInfo:\n");
  161.     printf("Width = %u, Height = %u\n",BMHDhead->bmh_Width, BMHDhead->bmh_Height);
  162.     printf("Depth = %u, Compre = %u\n",BMHDhead->bmh_Depth, BMHDhead->bmh_Compression);
  163.     printf("Mask  = %u\n",BMHDhead->bmh_Masking);
  164. #endif
  165.  
  166.     BCompression = BMHDhead->bmh_Compression;
  167.     
  168.     if (BMHDhead->bmh_Depth > 8)
  169.     {
  170.         MakeReq("AmiSlate Error","Sorry, AmiSlate only supports ILBMs of 256 colors or less","Rats");
  171.         CleanUpIFF(SlateIFF);
  172.         return(FALSE);
  173.     }
  174.     
  175.     /* Resize if requested */
  176.     if (*BOurExpand == TRUE) 
  177.     {
  178.         nNewWidth = (BMHDhead->bmh_Width + 57);
  179.         nNewHeight= (BMHDhead->bmh_Height + ScreenTitleHeight() + 36);
  180.  
  181.         if (nNewWidth  < DrawWindow->Width)  nNewWidth  = DrawWindow->Width;
  182.         if (nNewHeight < DrawWindow->Height) nNewHeight = DrawWindow->Height; 
  183.         
  184.         if ((nNewWidth != DrawWindow->Width)||(nNewHeight != DrawWindow->Height))
  185.         {
  186.             ReSizeWindow(nNewWidth, nNewHeight, TRUE);
  187.             if (BNetConnect == TRUE) 
  188.             {
  189.                 BIFFLoadPending    = TRUE;        /* flag for a return to IFF2() later */
  190.                 return(TRUE);
  191.             }
  192.         }
  193.     }
  194.     
  195.     /* if we got here, we either didn't need to expand the window 
  196.        or we aren't connected to anybody, so it's already been
  197.        expanded.  In any case, proceed immediately to the next bit. */
  198.     return(LoadIFF2());
  199. }
  200.  
  201.  
  202.  
  203.  
  204.  
  205. /* This is the continuation of LoadIFF1().  It will be called immediately
  206.    if no resizing was necessary, or when the resize is complete if resize
  207.    was necessary and we are connected to a partner. */
  208. BOOL LoadIFF2(void)
  209. {    
  210.     /* remove flag if set */
  211.     BIFFLoadPending = FALSE;
  212.  
  213.     /* Redisplay "displaying blah" message */
  214.     SetWindowTitle(szWinTitle);
  215.     
  216.     /* Now load in the ColorMap info */
  217.     CMAPProp = FindProp(SlateIFF, ID_ILBM, ID_CMAP);
  218.     if (CMAPProp == NULL)
  219.     {
  220.         if (MakeReq("AmiSlate Warning","Couldn't find ColorMap info, Continue anyway using false color?","Okay|Cancel") == 0)
  221.         {
  222.             CleanUpIFF(SlateIFF);
  223.             ReplyRexxIFF(FALSE);
  224.             return(FALSE);
  225.         }
  226.         /* Crappy default case:  Map each color to its pen */
  227.         for (i=0;i<(1<<BMHDhead->bmh_Depth);i++)
  228.             ubPenArray[i] = i % (1<<PState.ubDepth);
  229.     }
  230.     else
  231.     {
  232.         /* fill out our array of pens with the pen number
  233.            of the closest equivalent pen to each of the 
  234.            R,G,B values */
  235.         
  236.         /* Eventually, when we have an option to load the
  237.            picture's palette on to our palette, we will do
  238.            that here instead. */
  239.         CMAPdata = (UBYTE *) CMAPProp->sp_Data;
  240.  
  241.         /* Load in palette if set to do so */
  242.         if (*BOurLoadPalette == TRUE) 
  243.           for (i=0;i<((1<<BMHDhead->bmh_Depth)*3);i+=3)       
  244.             AdaptNewColor(CMAPdata[i]>>4, CMAPdata[i+1]>>4, CMAPdata[i+2]>>4, BPenMarked, TRUE);
  245.  
  246.         /* Correlate IFF's pens with our palette */
  247.         for (i=0;i<((1<<BMHDhead->bmh_Depth)*3);i+=3)       
  248.           ubPenArray[i/3] = MatchPalette(CMAPdata[i]>>4, CMAPdata[i+1]>>4,CMAPdata[i+2]>>4,FALSE,NULL, NULL);
  249.  
  250.     }
  251.  
  252.     /* Get canvas width and height */
  253.     x2 = 65000;    /* way off the right edge */
  254.     y2 = 65000;    /* way off the bottom edge */
  255.     FixPos(&x2, &y2);    /* fit them to the corner */
  256.     x1 = 0;        /* off left edge */
  257.     y1 = 0;        /* off top edge */
  258.     FixPos(&x1, &y1);    /* fit them to the corner */
  259.     
  260.     if (BMHDhead->bmh_Width < (x2-x1+1))
  261.         nOutputWidth = BMHDhead->bmh_Width;
  262.     else    nOutputWidth = (x2-x1+1);
  263.  
  264.     if (BMHDhead->bmh_Height < (y2-y1+1))
  265.         nOutputHeight = BMHDhead->bmh_Height;
  266.     else    nOutputHeight = (y2-y1+1);
  267.     
  268.     /* allocate buffers */
  269.     ubPixelArray = AllocMem(nOutputWidth,MEMF_ANY);        /* holds up to one row of delicious IFF pixels! */
  270.     ubByteArray  = AllocMem(nOutputWidth*8,MEMF_ANY);    /* holds up to 8 interbyteleaved rows */    
  271.     if ((ubPixelArray == NULL)||(ubByteArray == NULL))
  272.     {
  273.         MakeReq("AmiSlate Error","Couldn't allocate memory for IFF load buffers","Cancel");
  274.         CleanUpIFF(SlateIFF);
  275.         ReplyRexxIFF(FALSE);
  276.         return(FALSE);
  277.     }
  278.     
  279.     /* Set the raster to the picture's size */
  280.     PState.LocalRaster.nRX = 0;    /* Always load to upper left! */
  281.     PState.LocalRaster.nRY = 0;
  282.     FixPos(&PState.LocalRaster.nRX, &PState.LocalRaster.nRY);    /* Fix that... */
  283.     PState.LocalRaster.nRWidth = nOutputWidth;
  284.     PState.LocalRaster.nRHeight = nOutputHeight;
  285.     PState.LocalRaster.nRCurrentOffset = 0;
  286.     
  287.     OutputAction(FROM_IDCMP, COMMAND, COMMAND_SETRASTER, NOP_PAD, NOP_PAD, NOP_PAD, DEST_PEER|DEST_FILE);
  288.     
  289.     nBytesPerRow = (BMHDhead->bmh_Width + 15)/16;    /* now in words */
  290.     nBytesPerRow *= 2;        /* convert to bytes */
  291.     
  292.     if ((BCompression == COMP_NONE)||(BCompression == COMP_BYTERUN))
  293.     {        
  294.         /* Now the tough part--loading in the pixel bits themselves... */
  295.         for (i=0;i<nOutputHeight;i++)
  296.         {    
  297.           if (CheckForUserAbort() == TRUE) 
  298.           {
  299.               CleanUpIFF(SlateIFF);
  300.               ReplyRexxIFF(FALSE);
  301.               return(FALSE);
  302.           }
  303.                       
  304.           /* Reset buffer for this scanline = 8 bits per byte in each scanline */
  305.           memset(ubByteArray,0,nBytesPerRow<<3);
  306.                   
  307.           for (nPlane=0;nPlane<BMHDhead->bmh_Depth;nPlane++)
  308.           {
  309.             if (BCompression == COMP_BYTERUN)
  310.                  nBytesRead = DecompressBytes(SlateIFF, ubPixelArray, nBytesPerRow);
  311.             else nBytesRead = ReadChunkBytes(SlateIFF,ubPixelArray,nBytesPerRow);
  312.                 
  313.             if (nBytesRead < 0)
  314.             {
  315.                 sprintf(ubPixelArray,"Error (%i) Reading IFF, found in line %i\0",nBytesRead, i);
  316.                 MakeReq("AmiSlate Error",ubPixelArray,"Cancel");
  317.                 CleanUpIFF(SlateIFF);
  318.                 ReplyRexxIFF(FALSE);
  319.                 return(FALSE);
  320.             }
  321.             else
  322.             {
  323.             /* or in this row to the accumulative buffer */
  324.             OrRasterLine(ubPixelArray,ubByteArray,nPlane,nBytesPerRow);
  325.             }
  326.           }
  327.  
  328.           DecodeRasterLine(ubPenArray, ubByteArray, nOutputWidth, (i != (nOutputHeight-1)));
  329.  
  330.           /* Read mask plane and discard it, if there is one */
  331.           if (BMHDhead->bmh_Masking == MASK_HASMASK) 
  332.           {
  333.             if (BCompression == COMP_BYTERUN)
  334.                  nBytesRead = DecompressBytes(SlateIFF, ubPixelArray, nBytesPerRow);
  335.             else nBytesRead = ReadChunkBytes(SlateIFF,ubPixelArray,nBytesPerRow);
  336.           }
  337.         }     
  338.     }
  339.      else
  340.          MakeReq("AmiSlate Error","I don't know how to decompress this ILBM.","Cancel");
  341.                  
  342.     CleanUpIFF(SlateIFF);
  343.     ReplyRexxIFF(TRUE);
  344.     return(TRUE);
  345. }
  346.  
  347.  
  348. /* If there is a Rexx command hanging on the successful completion of
  349.    this load, then let him return with return code BWasSuccessful */
  350. static void ReplyRexxIFF(BOOL BWasSuccessful)
  351. {
  352.     /* If ARexx was waiting on this, let him go */
  353.         if (PState.uwRexxWaitMask & REXX_REPLY_IFFLOAD)
  354.         {    
  355.         /* prototype: ((struct rxd_waitevent *) *(&RexxState.array))->res.code1= &lCode1FromWhom; */
  356.         RexxState.rc = BWasSuccessful;
  357.     
  358.         SetStandardRexxReturns();
  359.         }
  360.     return;
  361. }
  362.  
  363.  
  364. /* Reads compressed ILBM data from SlateIFF and decompresses it into ubPixelArray until 
  365.    nBytesPerRow bytes have been filled. */
  366. static int DecompressBytes(struct IFFHandle * SlateIFF, UBYTE * ubPixelArray, int nBytesPerRow)
  367. {
  368.     int nLineCount = 0;    /* Start with zero bytes read */
  369.     BYTE bNextByte,bCopyByte;
  370.  
  371.     while (nLineCount < nBytesPerRow)
  372.     {
  373.         if (ReadChunkBytes(SlateIFF,&bNextByte,1) != 1) return(nLineCount);
  374.         if (bNextByte >= 0)
  375.         {
  376.             /* Copy the next n+1 bytes into the buffer */
  377.             if (ReadChunkBytes(SlateIFF,&ubPixelArray[nLineCount],bNextByte+1) != (bNextByte+1)) return(nLineCount);
  378.             nLineCount += bNextByte+1;
  379.         }
  380.         else if (bNextByte != -128)
  381.         {
  382.             /* Replicate the next byte 1-n times */
  383.             if (ReadChunkBytes(SlateIFF,&bCopyByte,1) != 1) return(nLineCount);
  384.             memset(&ubPixelArray[nLineCount],bCopyByte,1-bNextByte);
  385.             nLineCount += 1-bNextByte;
  386.         }
  387.     }
  388.     return(nLineCount);
  389. }
  390.  
  391.             
  392. void CleanUpIFF(struct IFFHandle * mySlateIFF)
  393. {
  394.     if (ubPixelArray != NULL) FreeMem(ubPixelArray,nOutputWidth);        /* holds up to one row of delicious IFF pixels! */
  395.     if (ubByteArray  != NULL) FreeMem(ubByteArray,nOutputWidth*8);        /* holds up to one row of delicious IFF pixels! */
  396.  
  397.     ubPixelArray = NULL;
  398.     ubByteArray = NULL;
  399.     
  400.     if (mySlateIFF == NULL) mySlateIFF = SlateIFF;    /* default--so that AmiSlate.c doesn't have to know about SlateIFF */
  401.     if (mySlateIFF == NULL) return;        /* SlateIFF is NULL?  Well, nevermind then. */
  402.     
  403.     CloseIFF(mySlateIFF);
  404.  
  405.     if (mySlateIFF->iff_Stream != NULL) Close(mySlateIFF->iff_Stream);
  406.     FreeIFF(mySlateIFF);
  407.  
  408.     if (mySlateIFF == SlateIFF) SlateIFF = NULL;
  409.     
  410.     return;
  411. }
  412.  
  413.  
  414.  
  415. /* Save the current canvas as an IFF to szFileName.  Return TRUE
  416.    if successful, else FALSE. */
  417. BOOL SaveIFF(char *szFileName)
  418. {
  419.     int nTop=0,nBot=99999,nLeft=0,nRight=99999;
  420.     int nWidth, nHeight, i, nY, nPlane, nBytesPerRow, nBytesInThisRow;
  421.     struct BitMapHeader newBMHDhead;
  422.     struct IFFHandle * WriteIFF = NULL;
  423.     struct ThreeUnsignedBytes OurPaletteEntry;
  424.     UWORD uwRGB;
  425.     
  426.     /* Get top left and bottom right co-ordinates */
  427.     FixPos(&nLeft, &nTop);
  428.     FixPos(&nRight, &nBot);
  429.     
  430.     nWidth  = nRight - nLeft + 1;
  431.     nHeight = nBot   - nTop  + 1;
  432.     
  433.     /* Fill out our header struct */
  434.     newBMHDhead.bmh_Width       = nWidth;
  435.     newBMHDhead.bmh_Height      = nHeight;
  436.     newBMHDhead.bmh_Left        = 0;
  437.     newBMHDhead.bmh_Top         = 0;
  438.     newBMHDhead.bmh_Depth       = Scr->RastPort.BitMap->Depth;
  439.     newBMHDhead.bmh_Masking     = MASK_NOMASK;
  440.  
  441.     if (nWidth > 32)    
  442.         newBMHDhead.bmh_Compression = COMP_BYTERUN;    
  443.     else    
  444.         newBMHDhead.bmh_Compression = COMP_NONE;    
  445.         
  446.     newBMHDhead.bmh_Pad         = 0;        /* unused */
  447.     newBMHDhead.bmh_Transparent = 0;        /* unused */
  448.     newBMHDhead.bmh_XAspect     = 1;        /* we're fudging this, at least for now! */
  449.     newBMHDhead.bmh_YAspect     = 1;
  450.     newBMHDhead.bmh_PageWidth   = Scr->Width;    /* um, this is okay, right? */
  451.     newBMHDhead.bmh_PageHeight  = Scr->Height;    
  452.  
  453. #ifdef DEBUG
  454.     printf("BitMapHeaderInfo:\n");
  455.     printf("Width = %u, Height = %u\n",newBMHDhead.bmh_Width, newBMHDhead.bmh_Height);
  456.     printf("Depth = %u, Compre = %u\n",newBMHDhead.bmh_Depth, newBMHDhead.bmh_Compression);
  457.     printf("Mask  = %u\n",newBMHDhead.bmh_Masking);
  458. #endif
  459.  
  460.     nBytesPerRow = (newBMHDhead.bmh_Width + 15)/16;    /* now in words */
  461.     nBytesPerRow *= 2;                /* convert to bytes */
  462.  
  463.     /* Make sure we have mem to do this */
  464.     if (PrepareTempRaster() == FALSE)
  465.     {
  466.         MakeReq("AmiSlate Error", "Not enough memory to save!", "How embarrassing");
  467.         return(FALSE);
  468.     }
  469.     
  470.     WriteIFF = AllocIFF();
  471.     if (WriteIFF == NULL) return(FALSE);
  472.     
  473.     WriteIFF->iff_Stream = Open(szFileName, MODE_NEWFILE);
  474.     if (WriteIFF->iff_Stream == NULL)
  475.     {
  476.         FreeIFF(WriteIFF);
  477.         return(FALSE);
  478.     }
  479.     
  480.     InitIFFasDOS(WriteIFF);
  481.     
  482.     if (OpenIFF(WriteIFF, IFFF_WRITE) != 0L)
  483.     {
  484.         Close(WriteIFF->iff_Stream);
  485.         FreeIFF(WriteIFF);
  486.         return(FALSE);
  487.     }
  488.  
  489.     /* Begin writing with the standard headers */
  490.     if (PushChunk(WriteIFF, ID_ILBM, ID_FORM, IFFSIZE_UNKNOWN) != 0L)
  491.     {
  492.         CleanUpIFF(WriteIFF);
  493.         return(FALSE);
  494.     }
  495.     if (PushChunk(WriteIFF, ID_ILBM, ID_BMHD, sizeof(struct BitMapHeader)) != 0L)
  496.     {
  497.         CleanUpIFF(WriteIFF);
  498.         return(FALSE);
  499.     }
  500.     
  501.     /* The BitMapHeader info */
  502.     if (WriteChunkBytes(WriteIFF, &newBMHDhead, sizeof(newBMHDhead)) < 0)
  503.     {
  504.         CleanUpIFF(WriteIFF);
  505.         return(FALSE);
  506.     }
  507.     PopChunk(WriteIFF);    /* Pop BitMapHeader */
  508.     
  509.     if (PushChunk(WriteIFF, ID_ILBM, ID_CMAP, 3*(1<<Scr->RastPort.BitMap->Depth)) != 0L)
  510.     {
  511.         CleanUpIFF(WriteIFF);
  512.         return(FALSE);
  513.     }
  514.     
  515.     /* Save palette info */
  516.       for (i=0;i<(1<<Scr->RastPort.BitMap->Depth);i++)
  517.       {
  518.           uwRGB = RGBComponents(i);
  519.         OurPaletteEntry.ubBlue  = (uwRGB     ) & 0x000F;
  520.                 OurPaletteEntry.ubGreen = (uwRGB >> 4) & 0x000F;
  521.                 OurPaletteEntry.ubRed   = (uwRGB >> 8) & 0x000F;
  522.  
  523.           /* Convert to 8-bit values */
  524.         OurPaletteEntry.ubBlue  |= (OurPaletteEntry.ubBlue   << 4);
  525.                 OurPaletteEntry.ubGreen |= (OurPaletteEntry.ubGreen  << 4);
  526.                 OurPaletteEntry.ubRed   |= (OurPaletteEntry.ubRed    << 4);
  527.       
  528.         if (WriteChunkBytes(WriteIFF, &OurPaletteEntry.ubRed, sizeof(UBYTE)) < 0)
  529.         {
  530.             CleanUpIFF(WriteIFF);
  531.             return(FALSE);
  532.         }
  533.         if (WriteChunkBytes(WriteIFF, &OurPaletteEntry.ubGreen, sizeof(UBYTE)) < 0)
  534.         {
  535.             CleanUpIFF(WriteIFF);
  536.             return(FALSE);
  537.         }
  538.         if (WriteChunkBytes(WriteIFF, &OurPaletteEntry.ubBlue, sizeof(UBYTE)) < 0)
  539.         {
  540.             CleanUpIFF(WriteIFF);
  541.             return(FALSE);
  542.         }    
  543.     }    
  544.     PopChunk(WriteIFF);
  545.  
  546.     /* Now write the body header and lastly the body */
  547.     if (PushChunk(WriteIFF, ID_ILBM, ID_BODY, IFFSIZE_UNKNOWN) != 0L)
  548.     {
  549.         CleanUpIFF(WriteIFF);
  550.         return(FALSE);
  551.     }
  552.     
  553.     /* Write body info */
  554.     /* format:
  555.     
  556.        scanline 0 :   bitplane 0
  557.                  bitplane 1
  558.                  ...
  559.                  bitplane (Depth-1)
  560.        scanline 1:    ...
  561.        ...
  562.        scanline (nHeight-1) */
  563.        
  564.     /* default: */
  565.     nBytesInThisRow = nBytesPerRow;
  566.  
  567.     for (nY=nTop; nY<(nTop+nHeight); nY++)
  568.     {
  569.         for (nPlane = 0; nPlane < Scr->RastPort.BitMap->Depth; nPlane++)
  570.         {
  571.             /* Copy row of pixels from appropriate window bitplane into our buffer */
  572.             GetBitRow(ubByteArray, nWidth, nY, nPlane);
  573.  
  574.             if (newBMHDhead.bmh_Compression == COMP_BYTERUN)
  575.                 nBytesInThisRow = CompressBytes(ubByteArray, nBytesPerRow);
  576.          
  577.             if (WriteChunkBytes(WriteIFF, ubByteArray, nBytesInThisRow) < 0)
  578.             {
  579.                 CleanUpIFF(WriteIFF);
  580.                 FreeTempRaster();
  581.                 return(FALSE);
  582.             }
  583.         }
  584.     }
  585.     FreeTempRaster();
  586.     PopChunk(WriteIFF);    /* Pop Body */
  587.     PopChunk(WriteIFF);    /* Pop Form */
  588.     CleanUpIFF(WriteIFF);    
  589.     return(TRUE);
  590. }
  591.  
  592.  
  593. /* Puts a row of 1-bit pixels in ubTempBuffer, from nPlane of nRow of the
  594.    AmiSlate window.  The row will be (nBytesPerRow*8) pixels long. */
  595. /* This function requires that the array ubTempBuffer be AT LEAST 
  596.    nBytesPerRow long, even though it will only output nBytesPerRow/8 bytes! */
  597. void GetBitRow(UBYTE * ubTempBuffer, int nNumPixels, int nRow, int nPlane)
  598. {
  599.     int i,nPixelCount=0,nRight;
  600.     UBYTE ubCurrentPen;
  601.     int nStartX=0;    /* will be set to the left edge of the window */
  602.     
  603.     FixPos(&nStartX,&nRow);        /* set nStartX */
  604.     
  605.     /* Read the array of pen numbers into the temp buffer */
  606.     ReadPixelArray8(DrawWindow->RPort, nStartX, nRow, nStartX+nNumPixels-1, nRow, ubTempBuffer, &tempRaster);
  607.  
  608.     nRight = nStartX+nNumPixels;
  609.     
  610.     for (i=nStartX;i<nRight;i++)
  611.     {
  612.         ubCurrentPen = ubTempBuffer[nPixelCount];
  613.         
  614.         /* Isolate the bit from our bitplane */
  615.         ubCurrentPen >>= nPlane;    /* shift it to bit 0 */     
  616.         ubCurrentPen  &= 0x1;        /* remove all other bits */
  617.  
  618.         /* Clear our byte if it's new */
  619.         if ((nPixelCount % 8) == 0) ubTempBuffer[nPixelCount>>3] = 0;
  620.  
  621.         /* If our bit is one, or it in to the array in the correct bit */
  622.         if (ubCurrentPen)
  623.         {
  624.             ubCurrentPen <<= (7-(nPixelCount % 8));
  625.             ubTempBuffer[nPixelCount>>3] |= ubCurrentPen;
  626.         }
  627.         nPixelCount++;
  628.     }
  629.     /* make sure the last bytes are 0 */
  630.     ubTempBuffer[((nPixelCount-1)>>3)+1] = 0;
  631.     
  632.     return;
  633. }
  634.  
  635.  
  636. /* Sets up a temporary area for ReadPixelArray8 to work with */
  637. BOOL PrepareTempRaster(void)
  638. {
  639.     int nPlane;
  640.     
  641.     /* As per page 253 of the RKM:Includes */
  642.     /* Make a copy of the window's RastPort */
  643.     memcpy(&tempRaster, DrawWindow->RPort, sizeof(struct RastPort));
  644.  
  645.     /* Now do the modifications described */
  646.     tempRaster.Layer = NULL;
  647.     tempRaster.BitMap = &rMsBitMap;
  648.     
  649.     rMsBitMap.BytesPerRow = (((DrawWindow->Width+15)>>4)<<1);
  650.     rMsBitMap.Rows          = 1;        /* only need 1 row */
  651.     rMsBitMap.Flags          = 0;        /* I guess? */
  652.     rMsBitMap.Depth          = Scr->RastPort.BitMap->Depth;    
  653.     for (nPlane = 0; nPlane < rMsBitMap.Depth; nPlane++)
  654.     {
  655.         rMsBitMap.Planes[nPlane] = AllocRaster(rMsBitMap.BytesPerRow*8, rMsBitMap.Rows);
  656.         if (rMsBitMap.Planes[nPlane] == NULL)
  657.         {
  658.             FreeTempRaster();
  659.             return(FALSE);
  660.         }
  661.     }
  662.     return(TRUE);
  663. }
  664.  
  665.  
  666. BOOL FreeTempRaster(void)
  667. {
  668.     int nPlane;
  669.     
  670.     for (nPlane = 0; nPlane < rMsBitMap.Depth; nPlane++)
  671.     {
  672.         if (rMsBitMap.Planes[nPlane] != NULL)
  673.         {
  674.             FreeRaster(rMsBitMap.Planes[nPlane], rMsBitMap.BytesPerRow*8, rMsBitMap.Rows);
  675.             rMsBitMap.Planes[nPlane] = NULL;    /* just to be safe */
  676.         }
  677.     }
  678.     return(TRUE);
  679. }
  680.     
  681.  
  682. /* Compresses the bits in ubBuffer in-place using byte-run compression. 
  683.    Returns the new width of the row after compression.  */
  684. int CompressBytes(UBYTE * ubInArray, int nWidth)
  685. {
  686.     BYTE ubOutArray[PIXELBUFFERSIZE];    /* holds up to one row of delicious IFF pixels! */
  687.     BYTE * ubTempOut = ubOutArray, * ubTempIn = ubInArray;
  688.     int nReturn;
  689.         
  690.     /* Return number of bytes in output array */
  691.     nReturn = PackRow((BYTE **) &ubTempIn, (BYTE **) &ubTempOut, nWidth);
  692.  
  693.     /* Put our data in the user's array */
  694.     memcpy(ubInArray,ubOutArray,nReturn);
  695.     
  696.     return(nReturn);
  697. }
  698.  
  699.  
  700.  
  701. /* Puts each bit in the ubPixel array into its proper spot in the
  702.    ubByteArray.  This is basically a one-line planar to chunky
  703.    conversion!  */
  704. static void OrRasterLine(UBYTE * ubPixelArray, UBYTE * ubByteArray,
  705.         int nPlaneOffset, int nBytesPerRow)
  706. {
  707.     int i;
  708.  
  709.    for (i=0;i<nBytesPerRow;i++)
  710.    {    
  711.      /* Given the ith byte of ubPixel Array, we need to spread each of
  712.         its bits out to a separate byte in the ubByteArray.   */
  713.       
  714.      ubByteArray[i*8+7] |= ((ubPixelArray[i] & 0x01)!=0) << nPlaneOffset;
  715.      ubByteArray[i*8+6] |= ((ubPixelArray[i] & 0x02)!=0) << nPlaneOffset;
  716.      ubByteArray[i*8+5] |= ((ubPixelArray[i] & 0x04)!=0) << nPlaneOffset;
  717.      ubByteArray[i*8+4] |= ((ubPixelArray[i] & 0x08)!=0) << nPlaneOffset;
  718.      ubByteArray[i*8+3] |= ((ubPixelArray[i] & 0x10)!=0) << nPlaneOffset;
  719.      ubByteArray[i*8+2] |= ((ubPixelArray[i] & 0x20)!=0) << nPlaneOffset;
  720.      ubByteArray[i*8+1] |= ((ubPixelArray[i] & 0x40)!=0) << nPlaneOffset;
  721.      ubByteArray[i*8+0] |= ((ubPixelArray[i] & 0x80)!=0) << nPlaneOffset;
  722.      
  723.    }   
  724.    
  725.    return;
  726. }
  727.  
  728.     
  729. /* Examines the scan line, compresses, draws, and transmits it!  */    
  730. /* Note that the input array should be a "chunky" array... i.e.  */
  731. /* an array of nWidth pen values.  We can just look use each pen */
  732. /* value to look up what color to send from our pen array.      */
  733. /*                                     */
  734. /* If BContinued is TRUE, we will add onto/draw more of the last */
  735. /* chunk on the next pass through, otherwise we'll add it in hre */
  736. static void DecodeRasterLine(UBYTE * ubPenArray, UBYTE * ubByteArray, int nWidth, BOOL BContinued)
  737. {
  738.     int x1, nTemp;
  739.     static int nCurrentPen = -1;
  740.     static ULONG ulCount = 0;
  741.     
  742.     /* Set initial color if unset */
  743.     if (nCurrentPen < 0) nCurrentPen = ubPenArray[ubByteArray[0]]; 
  744.     
  745.     for (x1=0; x1<nWidth; x1++)
  746.     {
  747.         nTemp = ubPenArray[ubByteArray[x1]];
  748.         
  749.         /* Careful about pixel overflow--we don't want to bump into the control codes
  750.            which start at 0xF0F0 */
  751.         if ((nTemp != nCurrentPen)||(ulCount >= 0xF000))
  752.         {
  753.             DrawRasterChunk(ulCount, RGBComponents(nCurrentPen), &PState.LocalRaster, &nCurrentPen);
  754.             nCurrentPen = nTemp;
  755.             ulCount = 1;
  756.         }
  757.         else
  758.             ulCount++;
  759.     }
  760.  
  761.     /* If we don't plan on doing any more lines, draw the last bit now */
  762.     if (BContinued == FALSE)
  763.     {
  764.         DrawRasterChunk(ulCount, RGBComponents(nCurrentPen), &PState.LocalRaster, &nCurrentPen);
  765.         
  766.         /* Reset to initial state */
  767.         ulCount = 0;
  768.         nCurrentPen = -1;
  769.     }
  770.     return;
  771. }
  772.  
  773.  
  774.  
  775. /* Given the 4-bit RGB values for a color, change the (non-marked) color in 
  776.    our palette that is closest to this color to the new color. */
  777. int AdaptNewColor(int red, int green, int blue, BOOL * BPenMap,BOOL BTransmit)
  778. {
  779.     BOOL BJustAlloced;
  780.     UWORD uwBestPen = MatchPalette(red, green, blue, FALSE, BPenMap, &BJustAlloced);
  781.     UWORD uwRGBComp, uwOldRGBComp = RGBComponents(uwBestPen);
  782.     UBYTE ubRed, ubGreen, ubBlue;
  783.     
  784.     uwRGBComp = (red<<8)|(green<<4)|(blue);    
  785.     if ((BJustAlloced == TRUE)||(uwRGBComp & 0x0FFF) == (uwOldRGBComp & 0x0FFF))
  786.     {
  787.         /* do nothing */
  788.     }
  789.     else
  790.     {
  791.         ubRed   = ((uwOldRGBComp >> 8) & 0x000F);
  792.         ubGreen = ((uwOldRGBComp >> 4) & 0x000F);
  793.         ubBlue  = (uwOldRGBComp & 0x000F);
  794.         if (abs(ubRed-red) > 1)     ubRed   = (red + ubRed) >> 1;
  795.                        else ubRed   = red;
  796.                       
  797.         if (abs(ubGreen-green) > 1) ubGreen = (green + ubGreen) >> 1;
  798.                         else ubGreen = green;
  799.                       
  800.         if (abs(ubBlue-blue) > 1)   ubBlue  = (blue + ubBlue) >> 1;
  801.                        else ubBlue  = blue;
  802.         uwRGBComp = (ubRed<<8)|(ubGreen<<4)|(ubBlue);
  803.     }        
  804.     if (uwBestPen != -1) AdjustColor(0,0,uwBestPen,&uwRGBComp,BTransmit);
  805.     return(uwBestPen);
  806. }
  807.  
  808.  
  809. #endif
  810.  
  811.